#include <iostream>
#include <boost/lexical_cast.hpp>

#include "Engine/Engine.h"
#include "Game/Game.h"

#include "Common/Utility.h"

namespace CNWoofer
{
	namespace Engine
	{
		Core::Core( void )
		{
			iEngineState = Common::ENGINE_MENU;
			iFPS, iFPSCounter = 0;

			mResMgr = new ResourceMgr;
			mRender = new Render;
			mSound = new Sound;
			pGlue = new Common::Glue;

			iEntityID = 0;
			iLastFrameTime = 0;

			pCurrentMap = NULL;
		}

		Core::~Core( void )
		{
			delete pGlue;
			delete mResMgr;
			delete mRender;
			delete mSound;
			delete mWindow;
		}

		int Core::Initialize( void )
		{
			mWindow = new sf::RenderWindow( sf::VideoMode( 640, 480, 32 ), "Codename Woofer" );

			if( !mWindow->isOpen() )
			{
				return -1;
			}

			mRender->SetWindow( mWindow );
			mRender->SetFont( (sf::Font*)mResMgr->LoadResource( "Data/arial.ttf" ) );

			mFPSClock.restart();
			mClock.restart();

			pCurrentMap = (Map*)mResMgr->LoadResource( "data/test.lvl" );

			BindKey( "menu", sf::Keyboard::Escape );
			BindKey( "up", sf::Keyboard::Up );
			BindKey( "down", sf::Keyboard::Down );
			BindKey( "enter", sf::Keyboard::Return );

			return 0;
		}

		void Core::Frame( void )
		{
			CalcFPS();
			UpdateKeys();
			Events();
			
			if( iEngineState == Common::ENGINE_GAME )
			{
				UpdateEntities();
			}

			mSound->Update();
		}

		int Core::Shutdown( void )
		{
			mWindow->close();

			return 0;
		}

		void Core::CalcFPS( void )
		{
			if( mFPSClock.getElapsedTime().asMilliseconds() < 1000 )
			{
				iFPSCounter++;
			}
			else
			{
				mFPSClock.restart();

				iFPS = iFPSCounter;
				iFPSCounter = 0;

				mWindow->setTitle( "Codename Woofer  FPS: " + boost::lexical_cast<std::string, int>( iFPS ) );
			}

			int time = mClock.getElapsedTime().asMilliseconds() ;

			iDelta = time - iLastFrameTime;

			iLastFrameTime = time;
		}

		void Core::Events( void )
		{
			sf::Event ev;

			while( mWindow->pollEvent( ev ) )
			{
				switch( ev.type )
				{
					case sf::Event::Closed:
						iEngineState = Common::ENGINE_SHUTDOWN;
						break;

					case sf::Event::KeyPressed:
						KeyPressed( ev.key.code );
						break;

					case sf::Event::KeyReleased:
						KeyReleased( ev.key.code );
						break;

					default:
						break;
				}
			}
		}
		
		void Core::UpdateKeys( void )
		{
			std::map<std::string, Button*>::iterator i = mSButtons.begin();

			while( i != mSButtons.end() )
			{
				if( i->second )
				{
					if( i->second->iState == Common::KEY_PRESSED )
					{
						i->second->iState = Common::KEY_HELD;
					}
				}

				i++;
			}
		}

		void Core::KeyPressed( int key )
		{
			if( mIButtons[key] )
			{
				if( mIButtons[key]->iState >=  Common::KEY_PRESSED )
				{
					mIButtons[key]->iState = Common::KEY_HELD;
				}
				else
				{
					mIButtons[key]->iState = Common::KEY_PRESSED;
				}
			}
		}

		void Core::KeyReleased( int key )
		{
			if( mIButtons[key] )
			{
				mIButtons[key]->iState = Common::KEY_RELEASED;
			}
		}

		int Core::GetKeyState( std::string name )
		{
			if( mSButtons[name] )
			{
				return mSButtons[name]->iState;
			}
			else
			{
				std::cout << "Unknown button: " << name << std::endl;
				return -1;
			}
			
		}

		void Core::BindKey( std::string name, int key )
		{
			Button* b = new Button;

			b->sName = name;
			b->iKeyCode = key;
			b->iState = Common::KEY_RELEASED;

			mIButtons[key] = b;
			mSButtons[name] = b;
		}
		
		int Core::GetFPS( void )
		{
			return iFPS;
		}

		int Core::GetDelta( void )
		{
			return iDelta;
		}

		int Core::GetState( void )
		{
			return iEngineState;
		}

		void Core::SetState( int state )
		{
			if( state >= 0 && state <= Common::ENGINE_MENU )
			{
				iEngineState = state;
			}
		}

		void Core::AddEntity( Common::Entity* entity )
		{
			if( entity )
			{
				entity->iUID = iEntityID++;

				entity->Spawn();

				mEntities[iEntityID] = entity;
			}
		}

		void Core::UpdateEntities( void )
		{
			std::map<int, Common::Entity*>::iterator i = mEntities.begin();

			while( i != mEntities.end() )
			{
				if( i->second->fNextUpdate <= mClock.getElapsedTime().asSeconds() || i->second->fNextUpdate == 0 )
				{
					i->second->Update();
				}

				if( i->second->iHealth < 1 )
				{
					i->second->Death();

					std::cout << "Entity deleted." << std::endl;

					delete i->second;

					mEntities.erase( i );
				}

				i++;
			}
		}
	}
}